home *** CD-ROM | disk | FTP | other *** search
/ The CICA Windows Explosion! / The CICA Windows Explosion! - Disc 2.iso / nt / emacssrc.zip / EMACSSRC.TAR / emacs-19.17 / src / xrdb.c < prev    next >
C/C++ Source or Header  |  1993-07-18  |  17KB  |  748 lines

  1. /* Deal with the X Resource Manager.
  2.    Copyright (C) 1990, 1993 Free Software Foundation.
  3.  
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2, or (at your option)
  7. any later version.
  8.  
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12. GNU General Public License for more details.
  13.  
  14. You should have received a copy of the GNU General Public License
  15. along with this program; see the file COPYING.  If not, write to
  16. the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  17.  
  18. /* Written by jla, 4/90 */
  19.  
  20. #ifdef emacs
  21. #include "config.h"
  22. #endif
  23.  
  24. #include <stdio.h>
  25.  
  26. #if 1 /* I'd really appreciate it if this code could go away...  -JimB */
  27. /* this avoids lossage in the `dual-universe' headers on AT&T SysV X11 */
  28. #ifdef USG5
  29. #define SYSV
  30. #include <unistd.h>
  31. #endif /* USG5 */
  32.  
  33. #endif /* 1 */
  34.  
  35. /* This should be included before the X include files; otherwise, we get
  36.    warnings about redefining NULL under BSD 4.3.  */
  37. #include <sys/param.h>
  38.  
  39. #include <X11/Xlib.h>
  40. #include <X11/Xatom.h>
  41. #if 0
  42. #include <X11/Xos.h>
  43. #endif
  44. #include <X11/X.h>
  45. #include <X11/Xutil.h>
  46. #include <X11/Xresource.h>
  47. #ifdef VMS
  48. #include "vms-pwd.h"
  49. #else
  50. #include <pwd.h>
  51. #endif
  52. #include <sys/stat.h>
  53.  
  54. #ifndef MAXPATHLEN
  55. #define MAXPATHLEN    256
  56. #endif
  57.  
  58. extern char *getenv ();
  59.  
  60. /* This does cause trouble on AIX.  I'm going to take the comment at
  61.    face value.  */
  62. #if 0
  63. extern short getuid ();        /* If this causes portability problems,
  64.                    I think we should just delete it; it'll
  65.                    default to `int' anyway.  */
  66. #endif
  67.  
  68. #ifdef __bsdi__
  69. extern struct passwd *getpwuid (uid_t);
  70. extern struct passwd *getpwnam (const char *);
  71. #else
  72. extern struct passwd *getpwuid ();
  73. extern struct passwd *getpwnam ();
  74. #endif
  75.  
  76. /* Make sure not to #include anything after these definitions.  Let's
  77.    not step on anyone's prototypes.  */
  78. #ifdef emacs
  79. #define malloc xmalloc
  80. #define realloc xrealloc
  81. #define free xfree
  82. #endif
  83.  
  84. char *x_get_string_resource ();
  85. static int file_p ();
  86.  
  87.  
  88. /* X file search path processing.  */
  89.  
  90.  
  91. /* The string which gets substituted for the %C escape in XFILESEARCHPATH
  92.    and friends, or zero if none was specified.  */
  93. char *x_customization_string;
  94.  
  95.  
  96. /* Return the value of the emacs.customization (Emacs.Customization)
  97.    resource, for later use in search path decoding.  If we find no
  98.    such resource, return zero.  */
  99. char *
  100. x_get_customization_string (db, name, class)
  101.      XrmDatabase db;
  102.      char *name, *class;
  103. {
  104.   char *full_name
  105.     = (char *) alloca (strlen (name) + sizeof ("customization") + 3);
  106.   char *full_class
  107.     = (char *) alloca (strlen (class) + sizeof ("Customization") + 3);
  108.   char *result;
  109.  
  110.   sprintf (full_name,  "%s.%s", name,  "customization");
  111.   sprintf (full_class, "%s.%s", class, "Customization");
  112.  
  113.   result = x_get_string_resource (db, full_name, full_class);
  114.  
  115.   if (result)
  116.     return strcpy ((char *) malloc (strlen (result) + 1), result);
  117.   else
  118.     return 0;
  119. }
  120.  
  121.  
  122. /* Expand all the Xt-style %-escapes in STRING, whose length is given
  123.    by STRING_LEN.  Here are the escapes we're supposed to recognize:
  124.  
  125.     %N    The value of the application's class name
  126.     %T    The value of the type parameter ("app-defaults" in this
  127.         context)
  128.     %S    The value of the suffix parameter ("" in this context)
  129.     %L    The language string associated with the specified display
  130.         (We use the "LANG" environment variable here, if it's set.)
  131.     %l    The language part of the display's language string
  132.         (We treat this just like %L.  If someone can tell us what
  133.          we're really supposed to do, dandy.)
  134.     %t    The territory part of the display's language string
  135.             (This never gets used.)
  136.     %c    The codeset part of the display's language string
  137.             (This never gets used either.)
  138.     %C    The customization string retrieved from the resource
  139.         database associated with display.
  140.         (This is x_customization_string.)
  141.  
  142.    Return the expanded file name if it exists and is readable, and
  143.    refers to %L only when the LANG environment variable is set, or
  144.    otherwise provided by X.
  145.  
  146.    ESCAPED_SUFFIX and SUFFIX are postpended to STRING if they are
  147.    non-zero.  %-escapes in ESCAPED_SUFFIX are expanded; STRING is left
  148.    alone.
  149.  
  150.    Return NULL otherwise.  */
  151.  
  152. static char *
  153. magic_file_p (string, string_len, class, escaped_suffix, suffix)
  154.      char *string;
  155.      int string_len;
  156.      char *class, *escaped_suffix, *suffix;
  157. {
  158.   char *lang = getenv ("LANG");
  159.  
  160.   int path_size = 100;
  161.   char *path = (char *) malloc (path_size);
  162.   int path_len = 0;
  163.  
  164.   char *p = string;
  165.  
  166.   while (p < string + string_len)
  167.     {
  168.       /* The chunk we're about to stick on the end of result.  */
  169.       char *next;
  170.       int next_len;
  171.  
  172.       if (*p == '%')
  173.     {
  174.       p++;
  175.  
  176.       if (p >= string + string_len)
  177.         next_len = 0;
  178.       else
  179.         switch (*p)
  180.           {
  181.           case '%':
  182.         next = "%";
  183.         next_len = 1;
  184.         break;
  185.  
  186.           case 'C':
  187.         next = (x_customization_string
  188.             ? x_customization_string
  189.             : "");
  190.         next_len = strlen (next);
  191.         break;
  192.  
  193.           case 'N':
  194.         next = class;
  195.         next_len = strlen (class);
  196.         break;
  197.  
  198.           case 'T':
  199.         next = "app-defaults";
  200.         next_len = strlen (next);
  201.         break;
  202.  
  203.           default:
  204.           case 'S':
  205.         next_len = 0;
  206.         break;
  207.  
  208.           case 'L':
  209.           case 'l':
  210.         if (! lang)
  211.           {
  212.             free (path);
  213.             return NULL;
  214.           }
  215.         
  216.         next = lang;
  217.         next_len = strlen (next);
  218.         break;
  219.           
  220.           case 't':
  221.           case 'c':
  222.         free (path);
  223.         return NULL;
  224.           }
  225.     }
  226.       else
  227.     next = p, next_len = 1;
  228.  
  229.       /* Do we have room for this component followed by a '\0' ?  */
  230.       if (path_len + next_len + 1 > path_size)
  231.     {
  232.       path_size = (path_len + next_len + 1) * 2;
  233.       path = (char *) realloc (path, path_size);
  234.     }
  235.       
  236.       bcopy (next, path + path_len, next_len);
  237.       path_len += next_len;
  238.  
  239.       p++;
  240.  
  241.       /* If we've reached the end of the string, append ESCAPED_SUFFIX.  */
  242.       if (p >= string + string_len && escaped_suffix)
  243.     {
  244.       string = escaped_suffix;
  245.       string_len = strlen (string);
  246.       p = string;
  247.       escaped_suffix = NULL;
  248.     }
  249.     }
  250.  
  251.   /* Perhaps we should add the SUFFIX now.  */
  252.   if (suffix)
  253.     {
  254.       int suffix_len = strlen (suffix);
  255.  
  256.       if (path_len + suffix_len + 1 > path_size)
  257.     {
  258.       path_size = (path_len + suffix_len + 1);
  259.       path = (char *) realloc (path, path_size);
  260.     }
  261.  
  262.       bcopy (suffix, path + path_len, suffix_len);
  263.       path_len += suffix_len;
  264.     }
  265.  
  266.   path[path_len] = '\0';
  267.  
  268.   if (! file_p (path))
  269.     {
  270.       free (path);
  271.       return NULL;
  272.     }
  273.  
  274.   return path;
  275. }
  276.  
  277.  
  278. static char *
  279. gethomedir ()
  280. {
  281.   int uid;
  282.   struct passwd *pw;
  283.   char *ptr;
  284.   char *copy;
  285.  
  286.   if ((ptr = getenv ("HOME")) == NULL)
  287.     {
  288.       if ((ptr = getenv ("USER")) != NULL)
  289.     pw = getpwnam (ptr);
  290.       else
  291.     {
  292.       uid = getuid ();
  293.       pw = getpwuid (uid);
  294.     }
  295.  
  296.       if (pw)
  297.     ptr = pw->pw_dir;
  298.     }
  299.  
  300.   if (ptr == NULL) 
  301.     return "/";
  302.  
  303.   copy = (char *) malloc (strlen (ptr) + 2);
  304.   strcpy (copy, ptr);
  305.   strcat (copy, "/");
  306.  
  307.   return copy;
  308. }
  309.  
  310.  
  311. static int
  312. file_p (path)
  313.      char *path;
  314. {
  315.   struct stat status;
  316.  
  317.   return (access (path, 4) == 0            /* exists and is readable */
  318.       && stat (path, &status) == 0        /* get the status */
  319.       && (status.st_mode & S_IFDIR) == 0);    /* not a directory */
  320. }
  321.  
  322.  
  323. /* Find the first element of SEARCH_PATH which exists and is readable,
  324.    after expanding the %-escapes.  Return 0 if we didn't find any, and 
  325.    the path name of the one we found otherwise.  */
  326.  
  327. static char *
  328. search_magic_path (search_path, class, escaped_suffix, suffix)
  329.      char *search_path, *class, *escaped_suffix, *suffix;
  330. {
  331.   register char *s, *p;
  332.  
  333.   for (s = search_path; *s; s = p)
  334.     {
  335.       for (p = s; *p && *p != ':'; p++)
  336.     ;
  337.       
  338.       if (*p == ':' && *(p + 1) == ':')
  339.     {
  340.       char *path;
  341.  
  342.       s = "%N%S";
  343.       path = magic_file_p (s, strlen (s), class, escaped_suffix, suffix);
  344.       if (path)
  345.         return path;
  346.  
  347.       s = p + 1;
  348.       continue;
  349.     }
  350.  
  351.       if (p > s)
  352.     {
  353.       char *path = magic_file_p (s, p - s, class, escaped_suffix, suffix);
  354.       if (path)
  355.         return path;
  356.     }
  357.  
  358.       if (*p == ':')
  359.     p++;
  360.     }
  361.  
  362.   return 0;
  363. }
  364.  
  365. /* Producing databases for individual sources.  */
  366.  
  367. #define X_DEFAULT_SEARCH_PATH "/usr/lib/X11/%L/%T/%N%C%S:/usr/lib/X11/%l/%T/%N%C%S:/usr/lib/X11/%T/%N%C%S:/usr/lib/X11/%L/%T/%N%S:/usr/lib/X11/%l/%T/%N%S:/usr/lib/X11/%T/%N%S"
  368.  
  369. static XrmDatabase
  370. get_system_app (class)
  371.      char *class;
  372. {
  373.   XrmDatabase db = NULL;
  374.   char *path;
  375.  
  376.   path = getenv ("XFILESEARCHPATH");
  377.   if (! path) path = X_DEFAULT_SEARCH_PATH;
  378.  
  379.   path = search_magic_path (path, class, 0, 0);
  380.   if (path)
  381.     {
  382.       db = XrmGetFileDatabase (path);
  383.       free (path);
  384.     }
  385.  
  386.   return db;
  387. }
  388.  
  389.  
  390. static XrmDatabase
  391. get_fallback (display)
  392.      Display *display;
  393. {
  394.   XrmDatabase db;
  395.  
  396.   return NULL;
  397. }
  398.  
  399.  
  400. static XrmDatabase
  401. get_user_app (class)
  402.      char *class;
  403. {
  404.   char *path;
  405.   char *file = 0;
  406.  
  407.   /* Check for XUSERFILESEARCHPATH.  It is a path of complete file
  408.      names, not directories.  */
  409.   if (((path = getenv ("XUSERFILESEARCHPATH"))
  410.        && (file = search_magic_path (path, class, 0, 0)))
  411.  
  412.       /* Check for APPLRESDIR; it is a path of directories.  In each,
  413.      we have to search for LANG/CLASS and then CLASS.  */
  414.       || ((path = getenv ("XAPPLRESDIR"))
  415.       && ((file = search_magic_path (path, class, "/%L/%N", 0))
  416.           || (file = search_magic_path (path, class, "/%N", 0))))
  417.       
  418.       /* Check in the home directory.  This is a bit of a hack; let's
  419.      hope one's home directory doesn't contain any %-escapes.  */
  420.       || (path = gethomedir (),
  421.       ((file = search_magic_path (path, class, "%L/%N", 0))
  422.        || (file = search_magic_path (path, class, "%N", 0)))))
  423.     {
  424.       XrmDatabase db = XrmGetFileDatabase (file);
  425.       free (file);
  426.       return db;
  427.     }
  428.   else
  429.     return NULL;
  430. }
  431.  
  432.  
  433. static XrmDatabase
  434. get_user_db (display)
  435.      Display *display;
  436. {
  437.   XrmDatabase db;
  438.   char *xdefs;
  439.  
  440. #ifdef PBaseSize        /* Cheap way to test for X11R4 or later.  */
  441.   xdefs = XResourceManagerString (display);
  442. #else
  443.   xdefs = display->xdefaults;
  444. #endif
  445.  
  446.   if (xdefs != NULL)
  447.     db = XrmGetStringDatabase (xdefs);
  448.   else
  449.     {
  450.       char *home;
  451.       char *xdefault;
  452.  
  453.       home = gethomedir ();
  454.       xdefault = (char *) malloc (strlen (home) + sizeof (".Xdefaults"));
  455.       strcpy (xdefault, home);
  456.       strcat (xdefault, ".Xdefaults");
  457.       db = XrmGetFileDatabase (xdefault);
  458.       free (home);
  459.       free (xdefault);
  460.     }
  461.  
  462. #ifdef XlibSpecificationRelease
  463. #if XlibSpecificationRelease >= 5
  464.   /* Get the screen-specific resources too.  */
  465.   xdefs = XScreenResourceString (DefaultScreenOfDisplay (display));
  466.   if (xdefs != NULL)
  467.     {
  468.       XrmMergeDatabases (XrmGetStringDatabase (xdefs), &db);
  469.       XFree (xdefs);
  470.     }
  471. #endif
  472. #endif
  473.  
  474.   return db;
  475. }
  476.  
  477. static XrmDatabase
  478. get_environ_db ()
  479. {
  480.   XrmDatabase db;
  481.   char *p;
  482.   char *path = 0, *home = 0, *host = 0;
  483.  
  484.   if ((p = getenv ("XENVIRONMENT")) == NULL)
  485.     {
  486.       home = gethomedir ();
  487.  
  488.       {
  489.     int host_size = 100;
  490.     host = (char *) malloc (host_size);
  491.     
  492.     for (;;)
  493.       {
  494.         host[host_size - 1] = '\0';
  495.         gethostname (host, host_size - 1);
  496.         if (strlen (host) < host_size - 1)
  497.           break;
  498.         host = (char *) realloc (host, host_size *= 2);
  499.       }
  500.       }
  501.  
  502.       path = (char *) malloc (strlen (home)
  503.                   + sizeof (".Xdefaults-")
  504.                   + strlen (host));
  505.       sprintf (path, "%s%s%s", home, ".Xdefaults-", host);
  506.       p = path;
  507.     }
  508.  
  509.   db = XrmGetFileDatabase (p);
  510.  
  511.   if (path) free (path);
  512.   if (home) free (home);
  513.   if (host) free (host);
  514.  
  515.   return db;
  516. }
  517.  
  518. /* External interface.  */
  519.  
  520. /* Types of values that we can find in a database */
  521.  
  522. #define XrmStringType "String"    /* String representation */
  523. XrmRepresentation x_rm_string;    /* Quark representation */
  524.  
  525. /* Load X resources based on the display and a possible -xrm option. */
  526.  
  527. XrmDatabase
  528. x_load_resources (display, xrm_string, myname, myclass)
  529.      Display *display;
  530.      char *xrm_string, *myname, *myclass;
  531. {
  532.   char *xdefs;
  533.   XrmDatabase user_database;
  534.   XrmDatabase rdb;
  535.   XrmDatabase db;
  536.  
  537.   x_rm_string = XrmStringToQuark (XrmStringType);
  538.   XrmInitialize ();
  539.   rdb = XrmGetStringDatabase ("");
  540.  
  541.   user_database = get_user_db (display);
  542.  
  543.   /* Figure out what the "customization string" is, so we can use it
  544.      to decode paths.  */
  545.   if (x_customization_string)
  546.     free (x_customization_string);
  547.   x_customization_string
  548.     = x_get_customization_string (user_database, myname, myclass);
  549.  
  550.   /* Get application system defaults */
  551.   db = get_system_app (myclass);
  552.   if (db != NULL)
  553.     XrmMergeDatabases (db, &rdb);
  554.  
  555.   /* Get Fallback resources */
  556.   db = get_fallback (display);
  557.   if (db != NULL)
  558.     XrmMergeDatabases (db, &rdb);
  559.  
  560.   /* Get application user defaults */
  561.   db = get_user_app (myclass);
  562.   if (db != NULL)
  563.     XrmMergeDatabases (db, &rdb);
  564.  
  565.   /* get User defaults */
  566.   if (user_database != NULL)
  567.     XrmMergeDatabases (user_database, &rdb);
  568.  
  569.   /* Get Environment defaults. */
  570.   db = get_environ_db ();
  571.   if (db != NULL)
  572.     XrmMergeDatabases (db, &rdb);
  573.   
  574.   /* Last, merge in any specification from the command line. */
  575.   if (xrm_string != NULL)
  576.     {
  577.       db = XrmGetStringDatabase (xrm_string);
  578.       if (db != NULL)
  579.     XrmMergeDatabases (db, &rdb);
  580.     }
  581.  
  582.   return rdb;
  583. }
  584.  
  585.  
  586. /* Retrieve the value of the resource specified by NAME with class CLASS
  587.    and of type TYPE from database RDB.  The value is returned in RET_VALUE. */
  588.  
  589. int
  590. x_get_resource (rdb, name, class, expected_type, ret_value)
  591.      XrmDatabase rdb;
  592.      char *name, *class;
  593.      XrmRepresentation expected_type;
  594.      XrmValue *ret_value;
  595. {
  596.   XrmValue value;
  597.   XrmName namelist[100];
  598.   XrmClass classlist[100];
  599.   XrmRepresentation type;
  600.  
  601.   XrmStringToNameList(name, namelist);
  602.   XrmStringToClassList(class, classlist);
  603.  
  604.   if (XrmQGetResource (rdb, namelist, classlist, &type, &value) == True
  605.       && (type == expected_type))
  606.     {
  607.       if (type == x_rm_string)
  608.     ret_value->addr = (char *) value.addr;
  609.       else
  610.     bcopy (value.addr, ret_value->addr, ret_value->size);
  611.  
  612.       return value.size;
  613.     }
  614.  
  615.   return 0;
  616. }
  617.  
  618. /* Retrieve the string resource specified by NAME with CLASS from
  619.    database RDB. */
  620.  
  621. char *
  622. x_get_string_resource (rdb, name, class)
  623.      XrmDatabase rdb;
  624.      char *name, *class;
  625. {
  626.   XrmValue value;
  627.  
  628.   if (x_get_resource (rdb, name, class, x_rm_string, &value))
  629.     return (char *) value.addr;
  630.  
  631.   return (char *) 0;
  632. }
  633.  
  634. /* Stand-alone test facilities.  */
  635.  
  636. #ifdef TESTRM
  637.  
  638. typedef char **List;
  639. #define arg_listify(len, list) (list)
  640. #define car(list) (*(list))
  641. #define cdr(list) (list + 1)
  642. #define NIL(list) (! *(list))
  643. #define free_arglist(list)
  644.  
  645. static List
  646. member (elt, list)
  647.      char *elt;
  648.      List list;
  649. {
  650.   List p;
  651.  
  652.   for (p = list; ! NIL (p); p = cdr (p))
  653.     if (! strcmp (elt, car (p)))
  654.       return p;
  655.  
  656.   return p;
  657. }
  658.  
  659. static void
  660. fatal (msg, prog, x1, x2, x3, x4, x5)
  661.     char *msg, *prog;
  662.     int x1, x2, x3, x4, x5;
  663. {
  664.     extern int errno;
  665.  
  666.     if (errno)
  667.       perror (prog);
  668.  
  669.     (void) fprintf (stderr, msg, prog, x1, x2, x3, x4, x5);
  670.     exit (1);
  671. }
  672.  
  673. main (argc, argv)
  674.     int argc;
  675.     char **argv;
  676. {
  677.   Display *display;
  678.   char *displayname, *resource_string, *class, *name;
  679.   XrmDatabase xdb;
  680.   List arg_list, lp;
  681.  
  682.   arg_list = arg_listify (argc, argv);
  683.  
  684.   lp = member ("-d", arg_list);
  685.   if (!NIL (lp))
  686.     displayname = car (cdr (lp));
  687.   else
  688.     displayname = "localhost:0.0";
  689.  
  690.   lp = member ("-xrm", arg_list);
  691.   if (! NIL (lp))
  692.     resource_string = car (cdr (lp));
  693.   else
  694.     resource_string = (char *) 0;
  695.  
  696.   lp = member ("-c", arg_list);
  697.   if (! NIL (lp))
  698.     class = car (cdr (lp));
  699.   else
  700.     class = "Emacs";
  701.  
  702.   lp = member ("-n", arg_list);
  703.   if (! NIL (lp))
  704.     name = car (cdr (lp));
  705.   else
  706.     name = "emacs";
  707.  
  708.   free_arglist (arg_list);
  709.  
  710.   if (!(display = XOpenDisplay (displayname)))
  711.     fatal ("Can't open display '%s'\n", XDisplayName (displayname));
  712.  
  713.   xdb = x_load_resources (display, resource_string, name, class);
  714.  
  715.   /* In a real program, you'd want to also do this: */
  716.   display->db = xdb;
  717.  
  718.   while (1)
  719.     {
  720.       char query_name[90];
  721.       char query_class[90];
  722.  
  723.       printf ("Name: ");
  724.       gets (query_name);
  725.  
  726.       if (strlen (query_name))
  727.     {
  728.       char *value;
  729.  
  730.       printf ("Class: ");
  731.       gets (query_class);
  732.  
  733.       value = x_get_string_resource (xdb, query_name, query_class);
  734.  
  735.       if (value != NULL)
  736.         printf ("\t%s(%s):  %s\n\n", query_name, query_class, value);
  737.       else
  738.         printf ("\tNo Value.\n\n");
  739.     }
  740.       else
  741.     break;
  742.     }
  743.   printf ("\tExit.\n\n");
  744.  
  745.   XCloseDisplay (display);
  746. }
  747. #endif /* TESTRM */
  748.